package cors

import (
	"net/http"
	"strconv"
	"strings"

	"baseService/internal/infrastructure/config"
	"baseService/internal/pkg/logger"

	"github.com/gin-gonic/gin"
)

// Middleware CORS中间件
type Middleware struct {
	config *config.CORSConfig
	logger logger.Logger
}

// NewCORSMiddleware 创建CORS中间件
func NewCORSMiddleware(config *config.CORSConfig, logger logger.Logger) *Middleware {
	return &Middleware{
		config: config,
		logger: logger,
	}
}

// Handler 中间件处理函数
func (m *Middleware) Handler() gin.HandlerFunc {
	return func(c *gin.Context) {
		// 如果CORS未启用，直接通过
		if !m.config.Enable {
			c.Next()
			return
		}

		origin := c.GetHeader("Origin")

		// 检查是否允许该来源
		if !m.isOriginAllowed(origin) {
			m.logger.Warnf("CORS: 不允许的来源 - origin: %s, path: %s", origin, c.Request.URL.Path)
			c.AbortWithStatus(http.StatusForbidden)
			return
		}

		// 设置CORS响应头
		m.setCORSHeaders(c, origin)

		// 处理预检请求
		if c.Request.Method == "OPTIONS" {
			m.handlePreflightRequest(c)
			return
		}

		// 继续处理请求
		c.Next()
	}
}

// isOriginAllowed 检查来源是否被允许
func (m *Middleware) isOriginAllowed(origin string) bool {
	// 如果没有Origin头，允许通过（非跨域请求）
	if origin == "" {
		return true
	}

	// 检查允许的来源列表
	for _, allowedOrigin := range m.config.AllowOrigins {
		if m.matchOrigin(origin, allowedOrigin) {
			return true
		}
	}

	return false
}

// matchOrigin 匹配来源
func (m *Middleware) matchOrigin(origin, allowedOrigin string) bool {
	// 完全匹配
	if allowedOrigin == "*" || allowedOrigin == origin {
		return true
	}

	// 通配符匹配（支持子域名）
	if strings.HasPrefix(allowedOrigin, "*.") {
		domain := strings.TrimPrefix(allowedOrigin, "*.")
		return strings.HasSuffix(origin, domain)
	}

	return false
}

// setCORSHeaders 设置CORS响应头
func (m *Middleware) setCORSHeaders(c *gin.Context, origin string) {
	// 设置允许的来源
	if origin != "" && m.isOriginAllowed(origin) {
		c.Header("Access-Control-Allow-Origin", origin)
	} else if len(m.config.AllowOrigins) == 1 && m.config.AllowOrigins[0] == "*" {
		c.Header("Access-Control-Allow-Origin", "*")
	}

	// 设置允许的方法
	if len(m.config.AllowMethods) > 0 {
		methods := strings.Join(m.config.AllowMethods, ", ")
		c.Header("Access-Control-Allow-Methods", methods)
	}

	// 设置允许的请求头
	if len(m.config.AllowHeaders) > 0 {
		headers := strings.Join(m.config.AllowHeaders, ", ")
		c.Header("Access-Control-Allow-Headers", headers)
	}

	// 设置暴露的响应头
	if len(m.config.ExposeHeaders) > 0 {
		exposeHeaders := strings.Join(m.config.ExposeHeaders, ", ")
		c.Header("Access-Control-Expose-Headers", exposeHeaders)
	}

	// 设置是否允许凭证
	if m.config.AllowCredentials {
		c.Header("Access-Control-Allow-Credentials", "true")
	}

	// 设置预检请求缓存时间
	if m.config.MaxAge > 0 {
		c.Header("Access-Control-Max-Age", strconv.Itoa(m.config.MaxAge))
	}
}

// handlePreflightRequest 处理预检请求
func (m *Middleware) handlePreflightRequest(c *gin.Context) {
	requestMethod := c.GetHeader("Access-Control-Request-Method")
	requestHeaders := c.GetHeader("Access-Control-Request-Headers")

	// 验证请求方法
	if requestMethod != "" && !m.isMethodAllowed(requestMethod) {
		m.logger.Warnf("CORS预检: 不允许的方法 - method: %s, origin: %s, path: %s", requestMethod, c.GetHeader("Origin"), c.Request.URL.Path)
		c.AbortWithStatus(http.StatusMethodNotAllowed)
		return
	}

	// 验证请求头
	if requestHeaders != "" && !m.areHeadersAllowed(requestHeaders) {
		m.logger.Warnf("CORS预检: 不允许的请求头 - headers: %s, origin: %s, path: %s", requestHeaders, c.GetHeader("Origin"), c.Request.URL.Path)
		c.AbortWithStatus(http.StatusForbidden)
		return
	}

	// 记录成功的预检请求
	m.logger.Debugf("CORS预检请求成功 - method: %s, headers: %s, origin: %s", requestMethod, requestHeaders, c.GetHeader("Origin"))

	// 返回成功状态
	c.Status(http.StatusNoContent)
	c.Abort()
}

// isMethodAllowed 检查方法是否被允许
func (m *Middleware) isMethodAllowed(method string) bool {
	for _, allowedMethod := range m.config.AllowMethods {
		if strings.EqualFold(allowedMethod, method) {
			return true
		}
	}
	return false
}

// areHeadersAllowed 检查请求头是否被允许
func (m *Middleware) areHeadersAllowed(requestHeaders string) bool {
	if requestHeaders == "" {
		return true
	}

	// 解析请求头
	headers := strings.Split(requestHeaders, ",")
	for _, header := range headers {
		header = strings.TrimSpace(header)
		if !m.isHeaderAllowed(header) {
			return false
		}
	}

	return true
}

// isHeaderAllowed 检查单个请求头是否被允许
func (m *Middleware) isHeaderAllowed(header string) bool {
	// 标准的安全头总是允许的
	safeHeaders := []string{
		"Accept",
		"Accept-Language",
		"Content-Language",
		"Content-Type",
		"Origin",
		"Referer",
		"User-Agent",
	}

	for _, safeHeader := range safeHeaders {
		if strings.EqualFold(header, safeHeader) {
			return true
		}
	}

	// 检查配置的允许头
	for _, allowedHeader := range m.config.AllowHeaders {
		if strings.EqualFold(allowedHeader, header) {
			return true
		}
		// 支持通配符
		if allowedHeader == "*" {
			return true
		}
	}

	return false
}

// GetConfig 获取CORS配置（用于调试）
func (m *Middleware) GetConfig() *config.CORSConfig {
	return m.config
}

// IsOriginAllowed 公开方法，用于其他地方检查来源是否允许
func (m *Middleware) IsOriginAllowed(origin string) bool {
	return m.isOriginAllowed(origin)
}

// DefaultConfig 获取默认CORS配置
func DefaultConfig() *config.CORSConfig {
	return &config.CORSConfig{
		Enable:       true,
		AllowOrigins: []string{"*"},
		AllowMethods: []string{
			"GET",
			"POST",
			"PUT",
			"DELETE",
			"OPTIONS",
			"PATCH",
		},
		AllowHeaders: []string{
			"Origin",
			"Content-Type",
			"Authorization",
			"X-Requested-With",
			"X-Request-ID",
		},
		ExposeHeaders: []string{
			"Content-Length",
			"X-Request-ID",
			"X-Response-Time",
		},
		AllowCredentials: true,
		MaxAge:           86400, // 24小时
	}
}

// SecureConfig 获取安全的CORS配置（生产环境推荐）
func SecureConfig(allowedOrigins []string) *config.CORSConfig {
	return &config.CORSConfig{
		Enable:       true,
		AllowOrigins: allowedOrigins, // 明确指定允许的域名
		AllowMethods: []string{
			"GET",
			"POST",
			"PUT",
			"DELETE",
			"OPTIONS",
		},
		AllowHeaders: []string{
			"Origin",
			"Content-Type",
			"Authorization",
			"X-Requested-With",
		},
		ExposeHeaders: []string{
			"Content-Length",
			"X-Request-ID",
		},
		AllowCredentials: true,
		MaxAge:           3600, // 1小时
	}
}

// DevelopmentConfig 获取开发环境CORS配置
func DevelopmentConfig() *config.CORSConfig {
	return &config.CORSConfig{
		Enable: true,
		AllowOrigins: []string{
			"http://localhost:3000", // React开发服务器
			"http://localhost:8080", // Vue开发服务器
			"http://127.0.0.1:3000",
			"http://127.0.0.1:8080",
		},
		AllowMethods: []string{
			"GET",
			"POST",
			"PUT",
			"DELETE",
			"OPTIONS",
			"PATCH",
		},
		AllowHeaders: []string{
			"Origin",
			"Content-Type",
			"Authorization",
			"X-Requested-With",
			"X-Request-ID",
			"Cache-Control",
		},
		ExposeHeaders: []string{
			"Content-Length",
			"X-Request-ID",
			"X-Response-Time",
		},
		AllowCredentials: true,
		MaxAge:           86400,
	}
}
